package com.middleware.parse;

import com.middleware.annotations.OrmParam;
import com.middleware.utils.CommonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class SqlParameterParser {

    private static final Logger log = LoggerFactory.getLogger(SqlParameterParser.class);
    // 解析SQL中的 #{param} 占位符
    public static ParsedSql parseParameters(String originalSql, Object[] args, Parameter[] parameters) {
        // 使用正则匹配 #{...}
        Pattern pattern = Pattern.compile("#\\{([^}]+)\\}");
        Matcher matcher = pattern.matcher(originalSql);

        //判断 parameters 是否为空,如果为空，就判断是否有匹配项，如果有就报错
        if (parameters == null || parameters.length == 0) {
            if (matcher.find()) {
                throw new RuntimeException("参数错误");
            }
            ParsedSql parsedSql = new ParsedSql();
            parsedSql.setFinalSql(originalSql);
            parsedSql.setParamValues(new ArrayList<>());
            parsedSql.setParameterNames(new ArrayList<>());
            return parsedSql;
        }
        //如果参数不为一，或者是 基本类型，包装类型，String 类型
        if (args.length != 1 || args[0].getClass().isPrimitive()
                || CommonUtil.isWrapperType(args[0].getClass())
                || args[0].getClass().equals(String.class)) {

            return parseMultipleParameters(parameters, args, matcher);

        }
        //如果这个参数是Map类型
        if(args[0] instanceof Map){
            return parseMapParameters(args,matcher);
        }else {
            return paresObjectParameters( args, parameters, matcher);
        }
    }


    private static ParsedSql parseMultipleParameters(Parameter[] parameters,Object[] args,Matcher matcher) {
        //获取所有参数的名称
        List<String> parameterNameList = Arrays.stream(parameters).map(parameter -> {
            //如果参数有 @OrmParam 注解
            if (parameter.isAnnotationPresent(OrmParam.class)) {
                OrmParam ormParam = parameter.getAnnotation(OrmParam.class);
                return ormParam.value();
            } else {
                return parameter.getName();
            }
        }).collect(Collectors.toList());


        ParsedSql parsedSql = new ParsedSql();
        List<Object> paramValues = new ArrayList<>();
        List<String> paramNames = new ArrayList<>();
        StringBuffer finalSql = new StringBuffer();
        while (matcher.find()){
            String paramName = matcher.group(1);
            matcher.appendReplacement(finalSql, "?");
            paramNames.add(paramName);
            //根据参数名获取参数的位置
            Object parameterValue = getParameterValue(parameterNameList, paramName, args);
            paramValues.add(parameterValue);
        }
        matcher.appendTail(finalSql);

        parsedSql.setFinalSql(finalSql.toString());
        parsedSql.setParamValues(paramValues);
        parsedSql.setParameterNames(paramNames);
        return parsedSql;
    }

    private static ParsedSql parseMapParameters(Object[] args,Matcher matcher) {
        ParsedSql parsedSql = new ParsedSql();
        List<Object> paramValues = new ArrayList<>();
        List<String> paramNames = new ArrayList<>();
        StringBuffer finalSql = new StringBuffer();
        Map<String, Object> paramMap;
        if(args[0] instanceof Map){
            paramMap = (Map<String, Object>) args[0];
        }else{
            throw new RuntimeException("参数错误");
        }
        while (matcher.find()){
            String paramName = matcher.group(1);
            Object value = paramMap.get(paramName);
            matcher.appendReplacement(finalSql, "?");
            paramNames.add(paramName);
            paramValues.add(value);
        }
        matcher.appendTail(finalSql);

        parsedSql.setFinalSql(finalSql.toString());
        parsedSql.setParamValues(paramValues);
        parsedSql.setParameterNames(paramNames);
        return parsedSql;
    }

    private static ParsedSql paresObjectParameters(Object[] args,Parameter[] parameters,Matcher matcher) {
        ParsedSql parsedSql = new ParsedSql();
        List<Object> paramValues = new ArrayList<>();
        List<String> paramNames = new ArrayList<>();
        StringBuffer finalSql = new StringBuffer();

        Class<?> parameterClass = parameters[0].getType();
        //将 args 转化成 parameterClass 类型
        Object parameterObject = parameterClass.cast(args[0]);
        Field[] declaredFields = parameterClass.getDeclaredFields();
        //用 stream 将这个参数对象转化成Map
        Map<String, Object> parameterMap = Arrays.stream(declaredFields)
                .map(field -> {
                    field.setAccessible(true);
                    try {
                        return new AbstractMap.SimpleEntry<>(field.getName(), field.get(parameterObject));
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                })
                // 过滤掉键为null的条目
                .filter(entry -> entry.getKey() != null && entry.getValue() != null)
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        (existing, replacement) -> existing, // 处理重复键的情况
                        HashMap::new // 明确指定Map实现
                ));

        while (matcher.find()){
            String paramName = matcher.group(1);
            matcher.appendReplacement(finalSql, "?");
            paramNames.add(paramName);
            paramValues.add(parameterMap.get(paramName));
        }
        matcher.appendTail(finalSql);
        parsedSql.setFinalSql(finalSql.toString());
        parsedSql.setParamValues(paramValues);
        parsedSql.setParameterNames(paramNames);
        return parsedSql;
    }

    private static Object getParameterValue(List<String> paramNameList,String paramName, Object[] args) {
        int paramIndex = paramNameList.indexOf(paramName);
        // 简单实现：按位置匹配
        if (paramIndex < args.length || paramIndex >= 0) {
            return args[paramIndex];
        }
        throw new RuntimeException("参数错误");
    }

}